package org.scribe.builder;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.scribe.builder.api.DefaultApi20;
import org.scribe.exceptions.OAuthException;
import org.scribe.extractors.AccessTokenExtractor;
import org.scribe.model.OAuthConfig;
import org.scribe.model.OAuthConstants;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuth20ServiceImpl;
import org.scribe.oauth.OAuthService;
import org.scribe.utils.OAuthEncoder;
import org.scribe.utils.Preconditions;

public class Google2Api extends DefaultApi20 {

	class Extractor implements AccessTokenExtractor
	{
	  private Pattern accessTokenPattern = Pattern.compile("\"access_token\"\\s*:\\s*\"(\\S*?)\"");

	  @Override
	  public Token extract(String response)
	  {
	    Preconditions.checkEmptyString(response, "Cannot extract a token from a null or empty String");
	    Matcher matcher = accessTokenPattern.matcher(response);
	    if(matcher.find())
	    {
	      return new Token(matcher.group(1), "", response);
	    }
	    else
	    {
	      throw new OAuthException("Cannot extract an acces token. Response was: " + response);
	    }
	  }

	}

	class ServiceImpl extends OAuth20ServiceImpl {

		private final OAuthConfig config;

		protected ServiceImpl(OAuthConfig config) {
			super(Google2Api.this, config);

			this.config = config;
		}

		@Override
		public Token getAccessToken(Token requestToken, Verifier verifier) {
			OAuthRequest request = new OAuthRequest(getAccessTokenVerb(),
					getAccessTokenEndpoint());
			request.addBodyParameter(OAuthConstants.CLIENT_ID,
					config.getApiKey());
			request.addBodyParameter(OAuthConstants.CLIENT_SECRET,
					config.getApiSecret());
			request.addBodyParameter(OAuthConstants.CODE,
					verifier.getValue());
			request.addBodyParameter(OAuthConstants.REDIRECT_URI,
					config.getCallback());
			request.addBodyParameter("grant_type", "authorization_code");
			if (config.hasScope())
				request.addBodyParameter(OAuthConstants.SCOPE,
						config.getScope());
			Response response = request.send();
			return getAccessTokenExtractor().extract(response.getBody());
		}
	}
	
	private static final String AUTHORIZATION_URL = 
			"https://accounts.google.com/o/oauth2/auth?client_id=%s&response_type=code&scope=%s&redirect_uri=%s";

	public Google2Api() {
	}

	@Override
	public String getAccessTokenEndpoint() {
		return "https://accounts.google.com/o/oauth2/token";
	}

	@Override
	public String getAuthorizationUrl(OAuthConfig config) {
		// Preconditions.checkValidUrl(config.getCallback(),
		// "Must provide a valid url as callback. Foursquare2 does not support OOB");
		Preconditions.checkNotNull(config.getScope(), "Scope is mandatory");
		return String.format(AUTHORIZATION_URL, 
				config.getApiKey(),
				config.getScope(),
				OAuthEncoder.encode(config.getCallback()));
	}

	
	@Override
	public AccessTokenExtractor getAccessTokenExtractor() {
		return new Extractor();
	}

	@Override
	public Verb getAccessTokenVerb() {
		return Verb.POST;
	}

	@Override
	public OAuthService createService(OAuthConfig config) {
		return new ServiceImpl(config);
	}


}
